#ifndef IOT_COMMUNICATION_MQTT_SENSOR_H_
#define IOT_COMMUNICATION_MQTT_SENSOR_H_
#include "mosquittopp.h"
#include "util/logger.h"

class MosquittoAPI: public mosqpp::mosquittopp
{
 public:
  typedef typename std::function<void(const mosquitto_message *)> Callback;

 private:
    const char *host;
    int port;
    int keepalive;
    std::unordered_map<std::string, Callback> callbacks_map_;
    void on_connect(int rc);
    void on_disconnect(int rc);
    void on_publish(int mid);
    void on_subscribe(int mid, int qos_count, const int *granted_qos);
    void on_unsubscribe(int mid);
    void on_message(const mosquitto_message *message)
    {
        for (const auto& callback : callbacks_map_) {
            callback.second(message);
        }
    }

 public:
    MosquittoAPI(const char *_host, int _port);
    MosquittoAPI();
    ~MosquittoAPI();
    bool PublishMessage(const void *_message, const char *_topic, int _qos)
    {
        this->publish(NULL, _topic, strlen((char *)_message), _message, _qos, false);
        return true;
    }
    bool SubscribeTopic(const char *_topic, int _qos,int *mid = nullptr)
    {
        this->subscribe(NULL, _topic, _qos);
        return true;
    }
    bool UnsubscribeTopic(int *mid, const char *_topic)
    {
        this->unsubscribe(NULL, _topic);
        return true;
    }

    template <class T> 
    void AddCallback(void (T::*fp)(const mosquitto_message *data), T* obj) {     
        AddCallback(std::bind(fp, obj, std::placeholders::_1));
    }

    void AddCallback(const Callback& callback, const std::string& name = "default") 
    {
        if (name != "default") {
            auto it = callbacks_map_.find(name);
            if (it != callbacks_map_.end()) {
                PrintI("Callback name:  %s already registed",name.c_str());
                return;
        }
        callbacks_map_.emplace(name, callback);
    } else {
        callbacks_map_.emplace(std::to_string(callbacks_map_.size()), callback);
    }
    }


};

#endif